/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 电子商务云服务平台
 * 创建日期 : 2016年6月28日
 * 修改历史 : 
 *     1. [2016年6月30日]修改文件 by chihouliang
 * 添加Javadoc注释，更新代码规范，静态工具类增加private构造函数
 */
package com.gavinwind.inspay.common.util;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

/**
 * Ftp操作工具类
 * @date 2010-11-20
 * @since JDK 1.5
 * @author dingkui
 * @version 1.0
 *
 */
public class FtpUtil {

    /**
     * apache的FTPClient，本工具类主要根据它，进行封装
     */
    private FTPClient ftpClient;

    /**
     * 数据类型：二进制数据
     */
    public static final int BINARY_FILE_TYPE = FTP.BINARY_FILE_TYPE;

    /**
     * 数据类型：ascii型
     */
    public static final int ASCII_FILE_TYPE = FTP.ASCII_FILE_TYPE;

    /**
     * 根据指定config相关信息，连接远程Ftp服务器
     * @param cFtpConfig ftp服务配置相关
     * @throws java.net.SocketException, IOException
     */
    public void connectServer(FtpConfig cFtpConfig) throws SocketException, IOException {
        String tServer = cFtpConfig.getServer();
        int tPort = cFtpConfig.getPort();
        String tUsername = cFtpConfig.getUsername();
        String tPassword = cFtpConfig.getPassword();
        String tLocation = cFtpConfig.getLocation();
        String tEncode = cFtpConfig.getEncode();
        connectServer(tServer, tPort, tUsername, tPassword, tLocation, tEncode);
    }

    /**
     * 链接远程ftp服务器
     * @param cServer 服务器ip
     * @param cPort 服务器端口
     * @param cUser 用户名
     * @param cPassword 密码
     * @param cPath 登陆后的默认路径
     * @param cEncode 服务器文件系统编码
     * @throws java.net.SocketException
     * @throws java.io.IOException
     */
    public void connectServer(String cServer, int cPort, String cUser, String cPassword, String cPath, String cEncode)
            throws SocketException, IOException {
        ftpClient = new FTPClient();
        if (null != cEncode && 0 != cEncode.length()) {
            ftpClient.setControlEncoding(cEncode);
        }
        ftpClient.connect(cServer, cPort);
        ftpClient.login(cUser, cPassword);
        setFileType(BINARY_FILE_TYPE);
        if (null != cPath && 0 != cPath.length()) {
            ftpClient.changeWorkingDirectory(cPath);
        }
    }

    /**
     * 设置文件类型
     * @param cFileType 文件类型编号
     * @throws java.io.IOException
     */
    public void setFileType(int cFileType) throws IOException {
        ftpClient.setFileType(cFileType);
    }

    /**
     * 关闭服务器连接
     * @throws java.io.IOException
     */
    public void closeServer() throws IOException {
        if (ftpClient.isConnected()) {
            ftpClient.disconnect();
        }
    }

    /**
     * 改变路径
     * @param cPath 新路径
     * @throws java.io.IOException
     */
    public boolean changeDirectory(String cPath) throws IOException {
        return ftpClient.changeWorkingDirectory(cPath);
    }

    /**
     * 创建目录
     * @param cPathName 目录名
     * @throws java.io.IOException
     */
    public boolean createDirectory(String cPathName) throws IOException {
        return ftpClient.makeDirectory(cPathName);
    }

    /**
     * 删除目录
     * @param cPath 目录名
     * @throws java.io.IOException
     */
    public boolean removeDirectory(String cPath) throws IOException {
        return ftpClient.removeDirectory(cPath);
    }

    /**
     * 删除指定目录下全部内容（子目录和文件）
     * @param cPath
     * @param cIsAll 确认标志位，true的时候全部删除
     * @throws java.io.IOException
     */
    public boolean removeDirectory(String cPath, boolean cIsAll) throws IOException {
        if (!cIsAll) {
            return removeDirectory(cPath);
        }

        FTPFile[] tFtpFileArr = ftpClient.listFiles(cPath);
        if (tFtpFileArr == null || tFtpFileArr.length == 0) {
            return removeDirectory(cPath);
        }

        for (FTPFile tFtpFile : tFtpFileArr) {
            String tName = tFtpFile.getName();
            if (tFtpFile.isDirectory()) {
                removeDirectory(cPath + "/" + tName, true);
            }
            else if (tFtpFile.isFile()) {
                deleteFile(cPath + "/" + tName);
            }
            else if (tFtpFile.isSymbolicLink()) {

            }
            else if (tFtpFile.isUnknown()) {

            }
        }
        return ftpClient.removeDirectory(cPath);
    }

    /**
     * 判断指定目录是否存在
     * @param cPath 指定路径
     * @return 存在则返回true，否则返回false
     * @throws java.io.IOException
     */
    public boolean existDirectory(String cPath) throws IOException {
        boolean tFlag = false;
        FTPFile[] tFtpFileArr = ftpClient.listFiles(cPath);
        for (FTPFile tFtpFile : tFtpFileArr) {
            if (tFtpFile.isDirectory() && tFtpFile.getName().equalsIgnoreCase(cPath)) {
                tFlag = true;
                break;
            }
        }
        return tFlag;
    }

    /**
     * 获得指定目录下的文件列表(含子目录)
     * @param cPath 指定目录
     * @return 文件列表
     * @throws java.io.IOException
     */
    public List<String> getFileList(String cPath) throws IOException {
        FTPFile[] tFtpFiles = ftpClient.listFiles(cPath);

        List<String> tRetList = new ArrayList<String>();
        if (tFtpFiles == null || tFtpFiles.length == 0) {
            return tRetList;
        }
        for (FTPFile tFtpFile : tFtpFiles) {
            if (tFtpFile.isFile()) {
                tRetList.add(tFtpFile.getName());
            }
        }
        return tRetList;
    }

    /**
     * 删除文件
     * @param cPathName 文件名
     * @return 成功返回true，失败返回false
     * @throws java.io.IOException
     */
    public boolean deleteFile(String cPathName) throws IOException {
        return ftpClient.deleteFile(cPathName);
    }

    /**
     * 上传文件（上传同时改名）
     * @param cFileName 原文件名
     * @param cNewName 上传后保存的文件名
     * @return 成功返回true，失败返回false
     * @throws java.io.IOException
     */
    public boolean uploadFile(String cFileName, String cNewName) throws IOException {
        boolean tFlag = false;
        InputStream tInputStream = null;
        try {
            tInputStream = new FileInputStream(cFileName);
            tFlag = ftpClient.storeFile(cNewName, tInputStream);
        }
        catch (IOException e) {
            tFlag = false;
            return tFlag;
        }
        finally {
            if (tInputStream != null) {
                tInputStream.close();
            }
        }
        return tFlag;
    }

    /**
     * 上传文件（保持原文件名）
     * @param cFileName 文件名
     * @return 成功返回true，失败返回false
     * @throws java.io.IOException
     */
    public boolean uploadFile(String cFileName) throws IOException {
        return uploadFile(cFileName, cFileName);
    }

    /**
     * 上传文件
     * @param cInputStream 上传文件的InputStream
     * @param cNewName 上传后保存的文件名
     * @return 成功返回true，失败返回false
     * @throws java.io.IOException
     */
    public boolean uploadFile(InputStream cInputStream, String cNewName) throws IOException {
        boolean tFlag = false;
        try {
            // can execute [OutputStream storeFileStream(String remote)]
            // Above method return's value is the local file stream.
            tFlag = ftpClient.storeFile(cNewName, cInputStream);
        }
        catch (IOException e) {
            tFlag = false;
            return tFlag;
        }
        finally {
            if (cInputStream != null) {
                cInputStream.close();
            }
        }
        return tFlag;
    }

    /**
     * 下载文件
     * @param cRemoteFileName 远程文件名
     * @param cLocalFileName 下载后，本地保存的文件名
     * @return 成功返回true，失败返回false
     * @throws java.io.IOException
     */
    public boolean download(String cRemoteFileName, String cLocalFileName) throws IOException {
        boolean tFlag = false;
        File tOutfile = new File(cLocalFileName);
        OutputStream tOutputStream = null;
        try {
            tOutputStream = new FileOutputStream(tOutfile);
            tFlag = ftpClient.retrieveFile(cRemoteFileName, tOutputStream);
        }
        catch (IOException e) {
            tFlag = false;
            return tFlag;
        }
        finally {
            tOutputStream.close();
        }
        return tFlag;
    }

    /**
     * 下载文件，将远程FTP文件，写入HttpServletResponse
     * @param cRemoteFileName 远程文件名
     * @param cResponse servlet的响应
     * @throws java.io.IOException
     */
    public void download(String cRemoteFileName, HttpServletResponse cResponse) throws IOException {

        if (ftpClient == null) {
            ftpClient = new FTPClient();
        }
        if (!ftpClient.isConnected()) {
            this.connectServer(new FtpConfig());
        }

        OutputStream tOutputStream = null;
        try {
            tOutputStream = cResponse.getOutputStream();
            ftpClient.retrieveFile(cRemoteFileName, tOutputStream);

        }
        catch (IOException e) {
            throw new RuntimeException("远程文件" + cRemoteFileName + "读入失败" + e.getMessage());
        }
        finally {
            if (tOutputStream != null) {
                tOutputStream.close();
            }
        }
        if (ftpClient != null) {
            if (ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
        }
    }

    /**
     * 取得远程文件的Stream
     * @param cSourceFileName
     * @return 取得远程文件的Stream
     * @throws java.io.IOException
     */
    public InputStream downFile(String cSourceFileName) throws IOException {
        return ftpClient.retrieveFileStream(cSourceFileName);
    }
}